package cn.com.wantools.module.nas.service.provider;

import cn.com.wantools.module.nas.enums.FileTypeEnum;
import cn.com.wantools.module.nas.model.FileNode;
import cn.com.wantools.module.nas.model.FileNodeList;
import cn.com.wantools.module.nas.model.PageExt;
import cn.com.wantools.module.nas.service.NasService;
import com.aliyun.oss.HttpMethod;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import io.jboot.aop.annotation.Bean;
import org.apache.commons.lang3.StringUtils;

import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Bean
public class NasServiceProvider implements NasService {
    private final String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
    // 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
    private final String accessKeyId = "LTAI5tP157p2c8wVFH7PTf6q";
    private final String accessKeySecret = "7rBpNbEBPbyTBDpdCFhqVxLXRqqLGY";
    private final String bucketName = "nas-wxx";

    @Override
    public OSS createOssClient() {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        return ossClient;
    }

    @Override
    public PageExt<FileNode> pageFileNodes(OSS ossClient, String path, Integer pageIndex, Integer pageSize, Integer totalSize, String nextContinuationToken) {
        List<FileNode> list = null;
        try {
            ListObjectsV2Request listObjectsV2Request = new ListObjectsV2Request(bucketName);
            listObjectsV2Request.setMaxKeys(pageSize);
            listObjectsV2Request.setPrefix(path);
            listObjectsV2Request.setDelimiter("/");
            if (StringUtils.isNotEmpty(nextContinuationToken)) {
                listObjectsV2Request.setContinuationToken(nextContinuationToken);
            }
            ListObjectsV2Result result = ossClient.listObjectsV2(listObjectsV2Request);
            List<OSSObjectSummary> ossObjectSummaries = result.getObjectSummaries();
            list = ossObjectSummaries.stream().map(summary -> {
                FileNode fileNode = new FileNode();
                fileNode.setPath(summary.getKey());
                fileNode.setFileName(getFileNameByPath(summary.getKey()));
                fileNode.setType(getFileType(summary.getKey()));
                fileNode.setSize(summary.getSize());
                fileNode.setBucketName(summary.getBucketName());
                fileNode.setStorageClass(summary.getStorageClass());
                if (getFileType(summary.getKey()).equals(FileTypeEnum.IMAGE.getFileType())) {
                    fileNode.setImgUrl(showImageUrl(ossClient, summary.getKey(), true));
                }
                return fileNode;
            }).collect(Collectors.toList());

            List<FileNode> folderNodeList = result.getCommonPrefixes().stream().map(s -> {
                FileNode fileNode = new FileNode();
                fileNode.setPath(s);
                fileNode.setFileName(getFileNameByPath(s));
                fileNode.setType("folder");
                fileNode.setSize(0L);
                fileNode.setBucketName(result.getBucketName());
                fileNode.setStorageClass("");
                return fileNode;
            }).collect(Collectors.toList());

            list.addAll(folderNodeList);

            for (OSSObjectSummary s : ossObjectSummaries) {
                System.out.println("\t" + s.getKey());
            }
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        }
        int totalPage = (int)Math.ceil(totalSize / pageSize);
        return new PageExt<>(list, pageIndex, pageSize, totalPage, totalSize, nextContinuationToken);
    }


    @Override
    public FileNodeList listFileNodes(OSS ossClient, String path, Integer pageSize, String nextContinuationToken) {
        List<FileNode> list = null;
        try {
            ListObjectsV2Request listObjectsV2Request = new ListObjectsV2Request(bucketName);
            listObjectsV2Request.setMaxKeys(pageSize);
            listObjectsV2Request.setPrefix(path);
            listObjectsV2Request.setDelimiter("/");
            if (StringUtils.isNotEmpty(nextContinuationToken)) {
                listObjectsV2Request.setContinuationToken(nextContinuationToken);
            }
            ListObjectsV2Result result = ossClient.listObjectsV2(listObjectsV2Request);
            nextContinuationToken = result.getNextContinuationToken();
            List<OSSObjectSummary> ossObjectSummaries = result.getObjectSummaries();
            list = result.getCommonPrefixes().stream().filter(s -> !path.equals(s)).map(s -> {
                FileNode fileNode = new FileNode();
                fileNode.setFileName(getFileNameByPath(s));
                fileNode.setPath(s);
                fileNode.setType("folder");
                fileNode.setSize(0L);
                fileNode.setBucketName(result.getBucketName());
                fileNode.setStorageClass("");
                return fileNode;
            }).collect(Collectors.toList());
            List<FileNode> listFileNode = ossObjectSummaries.stream().filter(s -> !path.equals(s.getKey())).map(summary -> {
                FileNode fileNode = new FileNode();
                fileNode.setPath(summary.getKey());
                fileNode.setFileName(getFileNameByPath(summary.getKey()));
                fileNode.setType(getFileType(summary.getKey()));
                fileNode.setSize(summary.getSize());
                fileNode.setBucketName(summary.getBucketName());
                fileNode.setStorageClass(summary.getStorageClass());
                if (getFileType(summary.getKey()).equals(FileTypeEnum.IMAGE.getFileType())) {
                    fileNode.setImgUrl(showImageUrl(ossClient, summary.getKey(), true));
                }

                return fileNode;
            }).collect(Collectors.toList());
            list.addAll(listFileNode);

            for (OSSObjectSummary s : ossObjectSummaries) {
                System.out.println("\t" + s.getKey());
            }
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        }
        FileNodeList fileNodeList = new FileNodeList();
        fileNodeList.setList(list == null ? new ArrayList<>() : list);
        fileNodeList.setNextContinuationToken(nextContinuationToken);
        return fileNodeList;
    }



    @Override
    public int listFileCount(OSS ossClient, String path) {
        ListObjectsV2Result result = null;
        int fileCount = 0;
        String nextContinuationToken = null;
        try {

            do {
                ListObjectsV2Request listObjectsV2Request = new ListObjectsV2Request(bucketName);
                listObjectsV2Request.setMaxKeys(100);
                listObjectsV2Request.setPrefix(path);
                if (nextContinuationToken != null) {
                    listObjectsV2Request.setContinuationToken(nextContinuationToken);
                }
                result = ossClient.listObjectsV2(listObjectsV2Request);
                List<OSSObjectSummary> ossObjectSummaries = result.getObjectSummaries();
                nextContinuationToken = result.getNextContinuationToken();
                fileCount += ossObjectSummaries.size();
                fileCount += result.getCommonPrefixes().size();
            }
            while (result.isTruncated());
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        }
        return fileCount;
    }

    @Override
    public int listFileCountWithSubFolder(OSS ossClient, String path) {
        ListObjectsV2Result result = null;
        int fileCount = 0;
        try {

            do {
                ListObjectsV2Request listObjectsV2Request = new ListObjectsV2Request(bucketName);
                listObjectsV2Request.setMaxKeys(100);
                listObjectsV2Request.setPrefix(path);
                result = ossClient.listObjectsV2(listObjectsV2Request);
                List<OSSObjectSummary> ossObjectSummaries = result.getObjectSummaries();
                fileCount += ossObjectSummaries.size();
                fileCount += result.getCommonPrefixes().size();
            }
            while (result.isTruncated());
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        }
        return fileCount;
    }

    @Override
    public PageExt<FileNode> listAllFileNodesWithSubFolder(OSS ossClient, String path, Integer pageIndex, Integer pageSize, Integer totalSize, String nextContinuationToken) {
        List<FileNode> list = null;
        boolean isTruncted  = false;
        try {
            ListObjectsV2Request listObjectsV2Request = new ListObjectsV2Request(bucketName);
            listObjectsV2Request.setMaxKeys(pageSize);
            listObjectsV2Request.setPrefix(path);
            if (nextContinuationToken != null) {
                listObjectsV2Request.setContinuationToken(nextContinuationToken);
            }
            ListObjectsV2Result result = ossClient.listObjectsV2(listObjectsV2Request);
            nextContinuationToken = result.getNextContinuationToken();
            isTruncted = result.isTruncated();
            List<OSSObjectSummary> ossObjectSummaries = result.getObjectSummaries();
            list = ossObjectSummaries.stream().map(summary -> {
                FileNode fileNode = new FileNode();
                fileNode.setPath(summary.getKey());
                fileNode.setFileName(getFileNameByPath(summary.getKey()));
                fileNode.setType(summary.getType());
                fileNode.setSize(summary.getSize());
                fileNode.setBucketName(summary.getBucketName());
                fileNode.setStorageClass(summary.getStorageClass());
                return fileNode;
            }).collect(Collectors.toList());
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        }
        int totalPage = (int) Math.ceil(totalSize / pageSize);
        return new PageExt<>(list, pageIndex, pageSize, totalPage, totalSize, nextContinuationToken, isTruncted);
    }

    static final List<String> IMG_EXTENSION_SET = Arrays.asList("jpg", "jpeg", "ico", "png", "bmp", "gif");
    static final List<String> DOC_EXTENSION_SET = Arrays.asList("doc", "docx");
    static final List<String> PDF_EXTENSION_SET = Arrays.asList("pdf");
    static final List<String> EXCEL_EXTENSION_SET = Arrays.asList("xls", "xlsx", "csv");
    static final List<String> PPT_EXTENSION_SET = Arrays.asList("ppt", "pptx");
    static final List<String> VIDEO_EXTENSION_SET = Arrays.asList("mp4", "mov", "wmv", "divx","xvid" ,"3ivx","rgp","h.263","h.264");
    static final List<String> AUDIO_EXTENSION_SET = Arrays.asList("mp3", "wav", "wma", "m4a");

    static final List<String> HTML_EXTENSION_SET = Arrays.asList("html", "htm");

    static final List<String> CSS_EXTENSION_SET = Arrays.asList("css");

    public String getFileType(String fileName) {
        String extension = "";
        int i = fileName.lastIndexOf('.');
        if (i > 0) {
            extension = fileName.substring(i + 1).toLowerCase();
        }
        if (IMG_EXTENSION_SET.contains(extension)) {
            return FileTypeEnum.IMAGE.getFileType();
        } else if (DOC_EXTENSION_SET.contains(extension)) {
            return FileTypeEnum.DOC.getFileType();
        } else if (PPT_EXTENSION_SET.contains(extension)) {
            return FileTypeEnum.PPT.getFileType();
        } else if (EXCEL_EXTENSION_SET.contains(extension)) {
            return FileTypeEnum.EXCEL.getFileType();
        } else if (VIDEO_EXTENSION_SET.contains(extension)) {
            return FileTypeEnum.VIDEO.getFileType();
        } else if (PDF_EXTENSION_SET.contains(extension)) {
            return FileTypeEnum.PDF.getFileType();
        } else if (AUDIO_EXTENSION_SET.contains(extension)) {
            return FileTypeEnum.AUDIO.getFileType();
        } else if (HTML_EXTENSION_SET.contains(extension)) {
            return FileTypeEnum.HTML.getFileType();
        } else if (CSS_EXTENSION_SET.contains(extension)) {
            return FileTypeEnum.CSS.getFileType();
        } else {
            return FileTypeEnum.OTHER.getFileType();
        }
    }

    private String getFileNameByPath(String path) {
        String[] splitPath = path.split("/");
        return splitPath[splitPath.length - 1].replace("/", "");
    }


    public String showImageUrl(OSS ossClient, String path, Boolean smallType) {
        if (smallType == null) {
            smallType = true;
        }
        try {

            // 指定签名URL过期时间为10分钟。
            Date expiration = new Date(new Date().getTime() + 1000 * 60 * 10);
            GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, path, HttpMethod.GET);
            req.setExpiration(expiration);
            if (smallType) {
                String style = "image/resize,m_lfit,w_250/quality,Q_35";
                req.setProcess(style);
            }

            URL signedUrl = ossClient.generatePresignedUrl(req);
            //System.out.println(signedUrl);
            return signedUrl.toString();
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        }
        return "";
    }

    public String showDocFileUrl(OSS ossClient, String path) {

        try {
            String style = "imm/previewdoc,copy_1";
            // 指定签名URL过期时间为10分钟。
            Date expiration = new Date(new Date().getTime() + 1000 * 60 * 10);
            GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, path, HttpMethod.GET);
            req.setExpiration(expiration);
            req.setProcess(style);
            URL signedUrl = ossClient.generatePresignedUrl(req);
            return signedUrl.toString();
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        }
        return "";
    }


    @Override
    public String showMediaUrl(OSS ossClient, String path) {

        try {
            // 指定签名URL过期时间为10分钟。
            Date expiration = new Date(new Date().getTime() + 1000 * 60 * 10);
            GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, path, HttpMethod.GET);
            req.setExpiration(expiration);
            URL signedUrl = ossClient.generatePresignedUrl(req);
            return signedUrl.toString();
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        }
        return "";
    }

    @Override
    public String showFileUrl(OSS ossClient, String path) {

        try {
            // 指定签名URL过期时间为10分钟。
            Date expiration = new Date(new Date().getTime() + 1000 * 60 * 10);
            GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, path, HttpMethod.GET);
            req.setExpiration(expiration);
            URL signedUrl = ossClient.generatePresignedUrl(req);
            return signedUrl.toString();
        } catch (OSSException oe) {
        }
        return "";
    }


    public String getETag(OSS ossClient, String path) {
        try {
            SimplifiedObjectMeta simplifiedObjectMeta = ossClient.getSimplifiedObjectMeta(bucketName, path);
            return simplifiedObjectMeta.getETag();
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        }
        return "";
    }

    public void shutdownOss(OSS ossClient) {
        if (ossClient != null) {
            ossClient.shutdown();
        }
    }
}
